﻿// RankingSejmowy 1.0 - Polish parliment statistics for the masses.
// Copyright (C) 2010 Jarosław Dubrownik
//  
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//  
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//  
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
using System;
using System.Collections.Generic;
using System.Linq;
using RankingSejmowy.DAL.Statistics;
using RankingSejmowy.Model;

namespace RankingSejmowy.BLL.Import.Calculations
{
    public abstract class CalculationBase
    {
        public Dictionary<Deputy, DeputyStatisticWithCount> CalculateDeputyStatistics(Cadence cadence)
        {
            var dict = new Dictionary<Deputy, DeputyStatisticWithCount>();

            foreach (var voting in cadence.GetVotings())
            {
                var dominantVote = GetPartyDominantVote(voting);
                CalculateSummary(voting.DeputiesVotes.ToArray(), dominantVote, dict);
            }

            return dict;
        }

        public DeputyStatistic[] GetTopDeputyStatistics(Dictionary<Deputy, DeputyStatisticWithCount> dictionary)
        {
            var statistics =
                dictionary.OrderByDescending(x => x.Value.Count).ThenBy(x => x.Key.Name).Take(10)
                    .Select(x => x.Value.DeputyStatistic).ToArray();

            DeputyStatisticHelper.UpdatePositions(statistics);
            return statistics;
        }

        public void CalculateSummary(DeputyVote[] deputyVotes, Dictionary<Party, EVote> partyDominantVotes,
                                     Dictionary<Deputy, DeputyStatisticWithCount> deputyStatistics)
        {
            foreach (var deputyVote in
                deputyVotes.Where(deputyVote => IsDeputyVoteMatching(partyDominantVotes, deputyVote)))
            {
                AddDeputyStatistic(deputyVote, deputyStatistics);
            }
        }

        public void AddDeputyStatistic(DeputyVote deputyVote,
                                       Dictionary<Deputy, DeputyStatisticWithCount> deputyStatistics)
        {
            DeputyStatisticWithCount statisticWithCount = null;
            if (!deputyStatistics.ContainsKey(deputyVote.Deputy))
            {
                var cadence = deputyVote.Voting.Meeting.Cadence;
                statisticWithCount = new DeputyStatisticWithCount
                                         {
                                             Count = 1,
                                             DeputyStatistic =
                                                 new DeputyStatistic
                                                     {
                                                         Cadence = cadence,
                                                         Deputy = deputyVote.Deputy,
                                                         Party = deputyVote.PartyCadence.Party,
                                                         StatisticType = GetStatisticType()
                                                     }
                                         };
                deputyStatistics.Add(deputyVote.Deputy, statisticWithCount);
            }
            else
            {
                statisticWithCount = deputyStatistics[deputyVote.Deputy];
                statisticWithCount.Count++;
            }
        }

        public Dictionary<Party, EVote> GetPartyDominantVote(Voting voting)
        {
            var voteGroups =
                voting.DeputiesVotes.GroupBy(x => x.PartyCadence.Party);
            var dict = new Dictionary<Party, EVote>();
            foreach (var voteGroup in voteGroups)
            {
                var topVotes =
                    voteGroup.GroupBy(x => x.Vote).OrderByDescending(x => x.Count()).Take(2).ToArray();
                if (topVotes.Length == 2 && topVotes[0].Count() == topVotes[1].Count())
                {
                    continue;
                }

                dict.Add(voteGroup.Key, topVotes[0].Key);
            }

            return dict;
        }

        public abstract EStatisticType GetStatisticType();

        public abstract bool IsDeputyVoteMatching(Dictionary<Party, EVote> partyDominantVotes, DeputyVote deputyVote);

        public DeputyStatistic[] Calculate(Cadence cadence)
        {
            var dictionary = CalculateDeputyStatistics(cadence);
            return GetTopDeputyStatistics(dictionary);
        }
    }
}